package com.camemax.dispatch.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.camemax.dispatch.pojo.Dispatch;
import com.camemax.dispatch.service.DispatchOrdersService;
import com.camemax.dispatch.service.DispatchService;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Service;

import java.util.UUID;

// ************************
// * @Date: 2021/6/21
// * @Author: Camemax
// * @Description: 订单服务实现类 - 实现【生成配单】业务代码
// ************************
@Service("dispatchOrdersService")
public class DispatchOrdersServiceImpl implements DispatchOrdersService {

    // 定义int类型属性，用于标记消费次数
    private int count = 1;

    @Autowired
    private DispatchService dispatchService;

    // 监听指定队列进行消费
    @RabbitListener( queues = {"orders-queue"} )
    @Override
    public void createDispatch(String message, @Header(AmqpHeaders.DELIVERY_TAG) long tag, Channel channel) {
        // 1. 控制台打印输出
        System.out.println("Rabbitmq 消费消息： [ " + message +  "] ==== 第 " + count ++ +"次！");

        // 2. 序列化消息，写入【配送表】
        Dispatch orderInfo = JSONObject.parseObject(message, Dispatch.class);
        Dispatch dispatchInfo = new Dispatch();
        dispatchInfo.setOrderId(orderInfo.getOrderId());
        dispatchInfo.setOrderContent(orderInfo.getOrderContent());

        dispatchInfo.setDispatchId(UUID.randomUUID().toString());
        dispatchInfo.setDispatcherId("Camemax");
        dispatchInfo.setDispatchStatus(1);

        // 3. 消费异常重试测试: 手动添加运行时异常
        // 解决消费重试的三种方案:
        //   | —— 1. 重试次数控制 + 死信队列
        //   | —— 2. try..catch + ack手动应答
        //   | —— 3. try..catch + ack手动应答 + 死信队列 + 人工干预

        // 使用该try取代下方的try，加上basicNack.requeue=true、acknowledge-mode: manual 则会导致重试机制失效
//        try {
        System.out.println(1/0); // 消费者将进行消费重试，产生死循环问题

        // 1. 执行【生成配单】数据库操作，将配单信息写入【配单服务】数据库
        int createResult = dispatchService.createDispatchOrder(dispatchInfo);

        if (createResult == 1){
            System.out.println("配送订单创建成功！配单号: " + orderInfo.getOrderId());
        }

        // 2. try..catch: 执行【生成配单】消息队列（rabbitmq）响应 以及 处理消费者在消费过程中的异常情况
        try {
            // 2.1 无异常的消费响应
            channel.basicAck(tag, false); // 参数声明: deliveryTag - 消费唯一键 ； multiple - 单/批次消费
        } catch (Exception x) {
            // 2.2 异常的消费响应
            try {
                // 2.2.1 参数声明:
                /*
                 * @param:deliveryTag - 消费唯一键 ；
                 * @param:multiple： 单/批次消费 ;
                 * @param:requeue 重发情况确认，true时重发，false时不重发
                 */
                channel.basicNack(tag, false, false);
            } catch (Exception ex) {
                ex.printStackTrace();
            }

        }
    }
}
